package com.lt.lumentracks.service.common;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.lt.lumentracks.constant.ErrorConstant.ChatErrorConstant;
import com.lt.lumentracks.context.BaseContext;
import com.lt.lumentracks.entity.po.ChatMessage;
import com.lt.lumentracks.entity.po.Conversation;
import com.lt.lumentracks.entity.po.ConversationUser;
import com.lt.lumentracks.entity.vo.chat.ConversationVO;
import com.lt.lumentracks.entity.vo.common.PageVO;
import com.lt.lumentracks.entity.vo.common.Result;
import com.lt.lumentracks.service.IChatMessageService;
import com.lt.lumentracks.service.IConversationService;
import com.lt.lumentracks.service.IConversationUserService;
import com.lt.lumentracks.service.IUserBlacklistService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

// 创建这个类的目的：解决 ChatMessageService 和 ConversationService 的循环依赖问题，将需要两个服务协同工作的方法放在这里
@Service
public class ConversationMessageService {

    @Autowired
    private IChatMessageService iChatMessageService;
    @Autowired
    private IConversationService iConversationService;
    @Autowired
    private IConversationUserService iConversationUserService;
    @Autowired
    private IUserBlacklistService iUserBlacklistService;


    // 新增消息
    @Transactional
    public Result<String> addMsg(ChatMessage cm) {
        // 如果任一一方拉黑，则不能继续发送消息
        Boolean isBlocked = iUserBlacklistService.isExistBlocked(cm.getReceiverId(), cm.getSenderId());
        if(isBlocked){
            return Result.error(ChatErrorConstant.CHATMSG_ADD_PRIVATE_CHAT_HASBEENBLOCKED);
        }

        // 1.如果当前消息是当前会话的第一条消息(消息的会话ID为null)，则创建新会话，并且默认为单聊，因为群聊消息的conversationId约定为不会为null
        if(cm.getConversationId() == null){
            if(cm.getReceiverId() == null){
                return Result.error(ChatErrorConstant.CONVERSATION_ADD_PRIVATE_CHAT_ARG_ERROR);
            }

            Conversation conv = new Conversation();
            conv.setConversationType(1); // 类型为单聊
            conv.setCreateBy(cm.getSenderId()); // 会话创建者id
            conv.setCreateTime(LocalDateTime.now()); // 创建时间

            iConversationService.addConversation(conv, cm.getReceiverId()); // 1.1.新增会话
            cm.setConversationId(conv.getId()); // 主键返回，设置会话id
        }

        // 2.查询某一方是否删除（清空）了会话，如果有，则修改清空状态，让他重新进入会话
        else {
            restoreConversation(cm.getConversationId(), cm.getSenderId(), cm.getReceiverId());
        }

        cm.setCreateTime(LocalDateTime.now());
        iChatMessageService.save(cm); // 3.新增消息

        // 返回消息id
        return Result.success(cm.getId().toString());
    }


    // 删除会话
    @Transactional
    public void removeConversation(Long conv_id) {

        Integer userId = BaseContext.getCurrentId(); // 当前用户id

        // 1.将当前用户对于当前会话的记录从【会话成员表(关联表)】中移除 --> 表现为：将加入会话的时间重置为null
        // 仅对当前用户来说，聊天会话以及相关记录变为不可见，其他用户仍可见聊天记录
        iConversationUserService.lambdaUpdate()
                .eq(ConversationUser::getConversationId, conv_id)
                .eq(ConversationUser::getUserId, userId)
                .set(ConversationUser::getCleanStatus, true) // 设置清空状态
                .set(ConversationUser::getLastCleanTime, LocalDateTime.now()) // 设置上次清空时间
                .update();

        // 2.若当前会话的成员数小于1，则将当前会话从【会话表】中移除，并且相关聊天记录也一并删除（可选）
//        QueryWrapper<ConversationUser> qw = new QueryWrapper<ConversationUser>()
//                .eq("conversation_id", conv_id)
//                .eq("create_time", null);
//
//        long count = iConversationUserService.count(qw); // 创建时间为null的会话成员数
//        if(count > 1){
//            // 2.1.将当前会话从【会话表】中移除
//            iConversationService.removeById(conv_id);
//
//            // 2.2.将当前会话从【会话成员表(关联表)】中移除
//            iConversationUserService.remove(qw);
//
//            // 2.3.相关聊天记录也一并删除，从【聊天记录表】中移除
//            iChatMessageService.remove(new QueryWrapper<ChatMessage>()
//                    .eq("conversation_id", conv_id));
//        }

    }


    // 查--根据会话id分页查询聊天记录
    public PageVO<ChatMessage> getMsgByPage(Long conversationId, long pageNum, long pageSize) {
        Integer userId = BaseContext.getCurrentId();

        // 查询这个用户是什么时候加入的会话，不能查询在这之前的信息
        ConversationUser cu = iConversationUserService.lambdaQuery()
                .eq(ConversationUser::getConversationId, conversationId)
                .eq(ConversationUser::getUserId, userId)
                .one();
        if(cu == null){
            return new PageVO<>();
        }
        LocalDateTime joinTime = cu.getCreateTime();
        LocalDateTime cleanTime = cu.getLastCleanTime();

        Page<ChatMessage> page = iChatMessageService.lambdaQuery()
                .eq(ChatMessage::getConversationId, conversationId)
                .eq(ChatMessage::getStatus, 1) // 正常状态
                .ge(ChatMessage::getCreateTime, joinTime) // 时间在加入该会话之后
                .ge(cleanTime != null, ChatMessage::getCreateTime, cleanTime) // 时间在清理记录之后
                .orderByDesc(ChatMessage::getCreateTime)
                .page(Page.of(pageNum, pageSize));

        return PageVO.of(page);
    }


    // 查--查询当前用户所加入的会话，返回会话列表
    public List<ConversationVO> queryByUser() {
        Integer userId = BaseContext.getCurrentId();

        // 1.查询原始数据
        List<Conversation> raw_list = iConversationService.queryRawByUser(userId);

        // 2.转换vo
        return wrapConversationVOList(raw_list, userId);
    }


    // 查--根据双方id查询会话信息，仅限私聊
    public ConversationVO getWhisperConversation(Integer talkerUid) {
        Integer currentId = BaseContext.getCurrentId();
        if (currentId != null && talkerUid != null) {
            List<Long> singleChat = iConversationUserService.getSingleChat(currentId, talkerUid);
            if (!singleChat.isEmpty()) {
                Conversation c = iConversationService.getById(singleChat.get(0));
                ChatMessage lastMsg = iChatMessageService.queryLastMessageByConversationIds(List.of(c.getId())).get(0);

                ConversationVO vo = new ConversationVO();
                BeanUtils.copyProperties(c, vo);

                if(lastMsg != null){
                    vo.setLastMessageId(lastMsg.getId());
                    vo.setLastMessageContent(lastMsg.getContent());
                    vo.setLastMessageTime(lastMsg.getCreateTime());
                    vo.setLastMessageSenderId(lastMsg.getSenderId());
                    vo.setLastMessageIsRevoked(lastMsg.getRevoked());
                }
                vo.setTalkerId(talkerUid);
                return vo;
            }
        }
        return null;
    }


    // 查--根据对话双方id查询聊天记录
    public PageVO<ChatMessage> getWhisperMsg(Integer talkerUid, long pageNum, long pageSize) {

        Integer currentId = BaseContext.getCurrentId(); // 当前用户id

        // 1.查会话id
        Long conversationId = Optional.ofNullable(iConversationUserService.getSingleChat(currentId, talkerUid))
                .filter(list -> !list.isEmpty()) // 确保列表不为空
                .map(list -> list.get(0)) // 获取第一个元素
                .orElse(null); // 如果列表为null、空或不存在第一个元素，则返回null

        // 2.根据会话id查询聊天记录
        return getMsgByPage(conversationId, pageNum, pageSize);
    }


    /** 批量查询（对于当前用户来说的）每个会话的未读消息数
     * @param c_list 用户已经加入的会话列表
     * @param userId 当前用户id
     * @return key为会话ID，value为未读消息数
     */
    public Map<Long, Long> countUnreadMessages(List<Conversation> c_list, Integer userId) {

        Map<Long, Long> map_vo = new HashMap<>();
        List<Long> cid_list = c_list.stream().map(Conversation::getId).toList();
        if(!cid_list.isEmpty()){
            List<Map<String, Object>> list = iConversationUserService.countUnreadMessages(cid_list, userId);
            map_vo = list.stream().collect(Collectors.toMap(
                    m -> Long.parseLong(m.get("conv_id").toString()),
                    m -> Long.parseLong(m.get("count").toString())
            ));
        }

        return map_vo;
    }




    // 封装ConversationVOList (Conversation --> ConversationVO)
    private List<ConversationVO> wrapConversationVOList (List<Conversation> rawList, Integer userId) {
        if (rawList == null || rawList.isEmpty()){ return List.of(); }

        // 1.提取所有会话ID，用于后续批量查询
        List<Long> rawIds = rawList.stream().map(Conversation::getId).toList();

        // 2. 批量查询用户【在这些会话中的关联信息】
        // 将查询结果转换为 Map<会话id, ConversationUser>，方便后续查找
        List<ConversationUser> cu_list = iConversationUserService.lambdaQuery()
                .eq(ConversationUser::getUserId, userId)
                .in(ConversationUser::getConversationId, rawIds)
                .list();
        Map<Long, ConversationUser> cuMap = cu_list.stream().collect(Collectors.toMap(
                ConversationUser::getConversationId,
                Function.identity()
        ));

        // 3. 批量查询每个会话的最后一条【消息】（需要用到窗口函数）
        // 同理，将查询结果转换为 Map，方便后续查找
        Map<Long, ChatMessage> lastMsgMap = iChatMessageService.queryLastMessageByConversationIds(rawIds)
                        .stream()
                        .collect(Collectors.toMap(ChatMessage::getConversationId, Function.identity()));

        // 4. 批量查询每个会话的未读消息数
        Map<Long, Long> unreadCountMap = this.countUnreadMessages(rawList, userId);

        // 5. 转换 VO (在内存中组装数据，无数据库查询)
        return rawList.stream().map(conv -> wrapConversationVO(conv, cuMap, lastMsgMap, unreadCountMap)).toList();
    }


    // 封装ConversationVO (Conversation --> ConversationVO)
    private ConversationVO wrapConversationVO (Conversation conv,
                                               Map<Long, ConversationUser> cuMap,
                                               Map<Long, ChatMessage> lastMsgMap,
                                               Map<Long, Long> unreadCountMap){
        class funcSetAttribute {
            public void setMsgAttribute(ChatMessage lastMsg, ConversationVO vo){
                vo.setLastMessageId(lastMsg.getId());
                vo.setLastMessageContent(lastMsg.getContent());
                vo.setLastMessageTime(lastMsg.getCreateTime());
                vo.setLastMessageSenderId(lastMsg.getSenderId());
                vo.setLastMessageIsRevoked(lastMsg.getRevoked());
                vo.setUnreadMessageCount(unreadCountMap.getOrDefault(conv.getId(), 0L));
            }
        }
        funcSetAttribute func = new funcSetAttribute();

        ConversationVO vo = new ConversationVO();

        // 1.拷贝原有属性
        BeanUtils.copyProperties(conv, vo);

        // 2.组装关联信息
        ConversationUser cu = cuMap.get(conv.getId()); // 从 Map 中获取当前会话的 ConversationUser 信息
        if (cu != null) {
            ChatMessage lastMsg = lastMsgMap.get(conv.getId());
            if (lastMsg == null) {
                return vo;
            }

            // 2.1.进入过的会话
            if(cu.getLastReadMessageId() != null){
                // 私聊 -- 显示未读数以及最新消息
                // 非私聊 -- 显示未读数以及最新消息
                func.setMsgAttribute(lastMsg, vo);

            }
            // 2.2.未进入过的会话
            else{
                // 私聊 -- 显示未读数以及最新消息
                if(conv.getConversationType() == 1){
                     func.setMsgAttribute(lastMsg, vo);
                }

                // 非私聊 -- 不显示未读以及最新消息，若有消息在“我”加入会话后发送，则从此条消息开始显示未读以及最新消息
                else {
                    // 在“我”加入非私聊会话之后发送的消息都算未读消息
                    if(lastMsg.getCreateTime().isAfter(cu.getCreateTime())){
                         func.setMsgAttribute(lastMsg, vo);
                    }
                }
            }
        }
        return vo;
    }


    // 设置用户重新加入会话
    private void restoreConversation(Long convId, Integer senderId, Integer receiverId) {
        List<ConversationUser> users = iConversationUserService.lambdaQuery()
                .eq(ConversationUser::getConversationId, convId)
                .in(ConversationUser::getUserId, senderId, receiverId)
                .list();

        List<Integer> toRestore = users.stream()
                .filter(ConversationUser::getCleanStatus)
                .map(ConversationUser::getUserId)
                .toList();

        if (!toRestore.isEmpty()) {
            iConversationUserService.lambdaUpdate()
                    .eq(ConversationUser::getConversationId, convId)
                    .in(ConversationUser::getUserId, toRestore)
                    .set(ConversationUser::getCleanStatus, false)
                    .update();
        }
    }

}
